#include "adaptneuron.h"
#include "math.h"
#include <stdio.h>

adaptneuron::adaptneuron()
{
   weight_step = 0.03;
}

adaptneuron::~adaptneuron()
{
}

void adaptneuron::setMaxError(double val)
{
   maxError = val;
}

void  adaptneuron::setCycleMaxCount(int val)
{
  cycle_max = val;
}

void adaptneuron::setExpSignal(int signalid, double val)
{
  exp_signal[signalid] = val;
}

neuron& adaptneuron::start(neuron& n_val)
{
  neuron_val = n_val;
  int    cycle_count = 0;
  double err_val = calcNeuronError();
  double err_val_bu = 0.0;
  int    synapse_id = 0;
  double synapse_w   = neuron_val.getSynapse(synapse_id).getWeight();
  double sign = 1.0;
  double synapse_w_tmp = synapse_w + (sign * synapse_w * 0.01);
  synapse syn;
  int    l_cicle_max = cycle_max * neuron_val.getSynapseCount();

   syn = neuron_val.getSynapse(synapse_id);
   syn.setWeight(synapse_w_tmp);
   neuron_val.setSynapse(syn, synapse_id);

/* select direction */
   sendAllSignals();
   err_val_bu = err_val;
   err_val = calcNeuronError();
   if(err_val > err_val_bu) {
     sign *= -1.0;
   }

  while(err_val > maxError && cycle_count++ < l_cicle_max) {
   sendAllSignals();
   err_val_bu = err_val;
   err_val = calcNeuronError();
//   printf("cicle: %d\n", cycle_count);

   if(err_val > err_val_bu) /* reject prev wieght */{
    sign *= -1.0;
    synapse_w_tmp = synapse_w_tmp + (sign * synapse_w_tmp * weight_step);
    syn = neuron_val.getSynapse(synapse_id);
    syn.setWeight(synapse_w_tmp);
    neuron_val.setSynapse(syn, synapse_id);
    err_val = err_val_bu;
   } else {
   	synapse_id ++;
   	if(synapse_id >= neuron_val.getSynapseCount())
   	  synapse_id  = 0;
	if(cycle_count >= l_cicle_max)
	 continue;

    syn = neuron_val.getSynapse(synapse_id);
    synapse_w_tmp = syn.getWeight();
    synapse_w = syn.getWeight();
    synapse_w = synapse_w + (sign * synapse_w * weight_step);
    syn.setWeight(synapse_w);
    neuron_val.setSynapse(syn, synapse_id);
   }
  }
  printf("Cicle count was used: %d max count: %d\n", cycle_count, l_cicle_max);
  return neuron_val;
}

void adaptneuron::sendAllSignals()
{
  const int signal_count_max = MAX_STUDY_SIGNAL_BUFFER;
  int signal_id = 0;

  for(; signal_id < signal_count_max; signal_id++)
  {
    neuron_val.setStudyBufferIndex(signal_id);
    neuron_val.calc_study();
    neuron_val.calc_back_study();
  }
}

double adaptneuron::calcNeuronError()
{
  const int signal_count_max = MAX_STUDY_SIGNAL_BUFFER;
  int signal_id = 0;
  double f_study;
  double b_study;
  double error = 0.;

  for(; signal_id < signal_count_max; signal_id++)
  {
    f_study = neuron_val.getAxon().getFStudySignal(signal_id);
    error += fabs(calcError(exp_signal[signal_id], f_study));
  }
  error = error / (double)signal_count_max;
  return error;
}

double adaptneuron::calcError(double fvalue, double svalue)
{
  double ret_value = 0.;
  if(fvalue != svalue)
    ret_value = (svalue - fvalue) / fabs(fvalue);
  return ret_value;
}
